1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import com.google.common.annotations.GwtCompatible;
20  
21  import java.util.Iterator;
22  import java.util.Map;
23  import java.util.Set;
24  
25  /**
26   * Workaround for
27   * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6312706">
28   * EnumMap bug</a>. If you want to pass an {@code EnumMap}, with the
29   * intention of using its {@code entrySet()} method, you should
30   * wrap the {@code EnumMap} in this class instead.
31   *
32   * <p>This class is not thread-safe even if the underlying map is.
33   *
34   * @author Dimitris Andreou
35   */
36  @GwtCompatible
37  final class WellBehavedMap<K, V> extends ForwardingMap<K, V> {
38    private final Map<K, V> delegate;
39    private Set<Entry<K, V>> entrySet;
40  
41    private WellBehavedMap(Map<K, V> delegate) {
42      this.delegate = delegate;
43    }
44  
45    /**
46     * Wraps the given map into a {@code WellBehavedEntriesMap}, which
47     * intercepts its {@code entrySet()} method by taking the
48     * {@code Set<K> keySet()} and transforming it to
49     * {@code Set<Entry<K, V>>}. All other invocations are delegated as-is.
50     */
51    static <K, V> WellBehavedMap<K, V> wrap(Map<K, V> delegate) {
52      return new WellBehavedMap<K, V>(delegate);
53    }
54  
55    @Override protected Map<K, V> delegate() {
56      return delegate;
57    }
58  
59    @Override public Set<Entry<K, V>> entrySet() {
60      Set<Entry<K, V>> es = entrySet;
61      if (es != null) {
62        return es;
63      }
64      return entrySet = new EntrySet();
65    }
66  
67    private final class EntrySet extends Maps.EntrySet<K, V> {
68      @Override
69      Map<K, V> map() {
70        return WellBehavedMap.this;
71      }
72  
73      @Override
74      public Iterator<Entry<K, V>> iterator() {
75        return new TransformedIterator<K, Entry<K, V>>(keySet().iterator()) {
76          @Override
77          Entry<K, V> transform(final K key) {
78            return new AbstractMapEntry<K, V>() {
79              @Override
80              public K getKey() {
81                return key;
82              }
83  
84              @Override
85              public V getValue() {
86                return get(key);
87              }
88  
89              @Override
90              public V setValue(V value) {
91                return put(key, value);
92              }
93            };
94          }
95        };
96      }
97    }
98  }